package com.wish233.model.protocol;

import com.wish233.model.protocol.enums.ProtocolMessageSerializerEnum;
import com.wish233.model.protocol.enums.ProtocolMessageTypeEnum;
import com.wish233.model.rpc.RpcRequest;
import com.wish233.model.rpc.RpcResponse;
import com.wish233.serializer.Serializer;
import com.wish233.serializer.factory.SerializerFactory;
import io.vertx.core.buffer.Buffer;

import java.io.IOException;

import static com.wish233.model.protocol.ProtocolConstant.MAGIC_HIGH;
import static com.wish233.model.protocol.ProtocolConstant.MAGIC_LOW;

/**
 * @author WHH
 * 协议解码器
 */
public class ProtocolDecoder {

    public static WishProtocol<?> decode(Buffer buffer) throws IOException {
        WishProtocol.Header header = new WishProtocol.Header();
        //获取魔数 校验
        byte magicHigh = buffer.getByte(0);
        byte magicLow = buffer.getByte(1);
        if (magicHigh != MAGIC_HIGH && magicLow != MAGIC_LOW) {
            throw new RuntimeException("非法协议！");
        }
        //读取协议头
        byte version = buffer.getByte(2);
        byte type = buffer.getByte(3);
        byte serializer = buffer.getByte(4);
        byte status = buffer.getByte(5);
        long requestId = buffer.getLong(6);
        //获取协议长度
        int bodyLen = buffer.getInt(14);
        //读取协议体
        byte[] body = buffer.getBytes(18, 18 + bodyLen);
        header.setMagicLow(magicLow);
        header.setMagicHigh(magicHigh);
        header.setVersion(version);
        header.setType(type);
        header.setSerializer(serializer);
        header.setRequestId(requestId);
        header.setStatus(status);
        header.setBodyLength(bodyLen);
        //获取序列化器
        ProtocolMessageSerializerEnum serializerEnum = ProtocolMessageSerializerEnum.getEnumByKey(serializer);
        if (serializerEnum == null) {
            throw new RuntimeException("序列化器" + header.getSerializer() + "不存在");
        }
        Serializer serializerInstance = SerializerFactory.getInstance(serializerEnum.getValue());
        //反序列化
        ProtocolMessageTypeEnum typeEnum = ProtocolMessageTypeEnum.getEnumByKey(type);
        if (typeEnum == null) {
            throw new RuntimeException("暂不支持的消息类型");
        }
        //返回
        switch (typeEnum) {
            case REQUEST:
                RpcRequest request = serializerInstance.deserialize(body, RpcRequest.class);
                return new WishProtocol<>(header, request);
            case RESPONSE:
                RpcResponse response = serializerInstance.deserialize(body, RpcResponse.class);
                return new WishProtocol<>(header, response);
            case HEART_BEAT:
            case OTHERS:
            default:
                throw new IOException("暂不支持！");
        }
    }
}
